Purpose: Using methods and working with files.
Goal: Complete as many of these questions as you can. If you are keeping up, you need to do at least the Core questions. The Additional questions are more challenging and are designed to stretch the more confident programmers. Don't worry if you can't do them now, but be prepared to come back and try them later on in the term.
Marking: All questions are binary marked.
To get a question marked, print out the program you have written and a cover
sheet from the 1b11 web page. Fill in the cover sheet and attach it to the
program listing, then take the work to your lab group demonstrator for marking.
The demonstrator may want to see a demonstration of your program running. An
answer can be submitted as many times as you like, until it is
satisfactory.
All printing should be done on the line printer (a4lp) - don't
use up your laser printer quota!
NOTE: You must keep all marked work as it forms a record of your progress. At the end of the course you are required to resubmit all work.
See the additional notes on the web about using files.
The following are examples of questions and answers, to show how the Java syntax works, and to illustrate the kinds of programs you should be writing. There are further examples in the text book.
Example 4.1 Write a program that has the following methods:
Hint: % is the division operator that returns the remainder. Try using it to divide by 10.
Answer:
// Written by A.Person, October 2000 // Answer to Ex4 example question 1 class Example4_1 { public int sumOfDigits(int n) { int sum = 0 ; n = Math.abs(n) ; while (n > 0) { sum += n % 10 ; n /= 10 ; } return sum ; } public void inputAndProcess(KeyboardInput in) { System.out.print("Type an integer: ") ; int n = in.readInteger() ; System.out.print("The sum of the digits of: " + n) ; System.out.println(" is: " + sumOfDigits(n)) ; // Note that the method call sumOfDigits is // is on the same object, so does not need // the object to be explicitly given. } // The main method should do no more than create the objects // and call a method to do the work. public static void main(String[] args) { KeyboardInput in = new KeyboardInput() ; Example4_1 myObject = new Example4_1() ; myObject.inputAndProcess(in) ; } }
Further thoughts:
Example 4.2 Write a program that asks for the name of a text file, and calls a method to read each line of text in the file, displaying each line on the screen.
// Written by A.Person, October 2000 // Answer to Ex4 example question 2 class Example4_2 { public void displayFile(String filename) { FileInput fileIn = new FileInput(filename) ; String s = fileIn.readString() ; while (!fileIn.eof()) { System.out.println(s) ; s = fileIn.readString() ; } fileIn.close() ; // Always close a file after it has been used. } public static void main(String[] args) { KeyboardInput in = new KeyboardInput() ; System.out.print("Enter filename: ") ; String filename = in.readString() ; Example4_2 myObject = new Example4_2() ; myObject.displayFile(filename) ; } }
This uses the FileInput class (see the notes or web page). Note the way that data is read from the file in the while loop. The eof() method will return true when an attempt has been made to read data from beyond the end of the file (not simply when the end of file has been reached).
Example 4.3 Write a program that uses a method to display a multiplication table, given an integer between 2 and 12 inclusive. The program should ask the user which table to display and reject any invalid request.
Notes: With most of the previous exercises you only really thought and planned in terms of a single statement sequence. However, now you know how to write methods, you want to update your strategy and first consider the design in terms of methods.
Obviously there will be a method that displays the multiplication table, which can be called displayTable. This will take an integer parameter but does not need to return a result, so can be declared as void displayTable(int n). Equally obvious, there will be a main method, as all programs must have one. However, should the main method ask the user for input and call displayTable, or should that behaviour be put into another method?
The answer to this question lies in an important method design principle: each method should be cohesive — that is, it should focus on doing one, and only one, well-defined chunk of behaviour needed by the program. Following this principle, the main method can focus on initializing the program by creating an object and then call another method to handle the user input. That method in turn can then focus on doing one thing before calling the method to display the table. Hence, we now have a method called doTable, and established which method calls another.
With the methods and their behaviour identified, each can now be looked at in turn to design their respective method bodies. Moreover, rather than having to consider the entire statement sequence in the program at one go, we are now concerned only with small portions at a time. This has divided a larger and more complex design problem into a collection of smaller, and more easily designed, components. Further each component has a well-defined interface by which it connects to other components. The interface is the name of the method and its parameter list, i.e. the number and types of the parameters. The design of each method is now straightforward. Method displayTable needs a loop and output statements to display a multiplication table, while doTable asks the user to enter a value and checks it is within the supported range. If it is then displayTable is called, otherwise an error message is displayed.
// Written by A.Person, October 2000 // Answer to Ex4 example question 3 // Program to display a multiplication table. public class MultiplicationTable { // Display multiplication table for n. public void displayTable(final int n) { int counter = 1 ; System.out.println("The " + n + " times table") ; while (counter < 13) { System.out.print(counter + " x " + n) ; System.out.println(" = " + counter * n) ; counter = counter + 1 ; } } // Input table to be displayed and get it displayed. public void doTable() { KeyboardInput in = new KeyboardInput () ; System.out.print("Which table (2-12)? ") ; int x = in.readInteger() ; if ((x < 2) || (x > 12)) { System.out.println("Cannot display that table") ; } else { displayTable(x) ; } } public static void main(final String[] args) { MultiplicationTable myTable = new MultiplicationTable() ; myTable.doTable() ; } }
Further thoughts: Note where the KeyboardInput object is created in this program. Is this the correct decision?
A method name should be chosen to help describe what the method does. Are the names chosen in these example programs good enough or can you suggest better names?
Example 4.4 Write a program that determines whether a word or
sentence is a palindrome. (A palindrome reads backwards the same way as
forwards, for example: ‘Able was I ere I saw Elba’.) Spaces are considered as
significant.
Notes: The problem statement gives little information about designing the
program, so we definitely need to do some thinking and planning before trying to
write code. First of all we need an algorithm to test whether a string is a
palindrome. This turns out to be easy:
make a copy of the string reverse the order of the characters compare the reversed copy with the original to see if they are the same
Now that we know that it’s possible to check for a palindrome, the next step
is to consider the overall sequence of events that should take place when the
program runs. This gives:
input string to test make a copy do the reverse check the reverse copy against the original display answer
Next we want to determine what methods are required and allocate behaviour to
them. We could bundle everything into a single method but that would violate our
cohesion guidelines. Instead, we identify the following methods:
String getInput() // Get the input string to be tested void testForPalindrome(String s) // Check if s is a palindrome boolean check(String s1, String s2) // Is s2 the reverse of s1? String reverse(String s) // Return the reverse of the argument String
This may seem more methods than necessary. That could turn out to be true but
at this stage we are deliberately breaking the overall behaviour down into
minimally sized methods to get a good feel for the design. Methods can be
combined and behaviour re-allocated later if it seems appropriate.
With the methods identified, each can be considered in turn to design its
method body. Method getInput is easy as it simply requests input and
returns the resulting string. TestForPalindrome is also straightforward,
it just need to call the check method with the same string for both
parameter values. Check is a bit more interesting as the decision has
been made to make it more general purpose than is strictly necessary for this
version of the program. The idea for check is that it can actually test
any two strings to see if they are the reverse of each other.
TestForPalindrome will call it with the same string for both arguments
since it checks for self-reversed strings. Check works by reversing one
string and then doing a string comparison using the compareTo method in
the String class.
This leaves reverse, which requires a bit more work. The basic
strategy here is to unpack the original string character by character and
reassemble the characters in the reverse order to create a new string. To find
out how to extract individual characters from a string we need to return the
documentation for class String. This shows that there is a method
declared as char charAt(int index), which returns the character at
position index, counting from 0 as the position of the first character. The
String documentation also shows a method int length() that returns
the number of characters in a String. With these methods we can construct
a loop to access each character in turn:
// Given some String s int position = 0; while (position < s.length()) { // Characters run from 0 to length-1 ...s.charAt(position) ; // Get the character and do something with i position = position + 1 ; // Move to next character }
Building the new string requires a search of the J2SDK documentation to
find a method to join a char to a String. The String class does
not provide one, so we start looking at other classes. It turns out there is a
class Character, whose objects represent characters, that can be used to
create a String from a single char using an expression like:
// Given a char c ... new Character(c).toString() ...
The toString() method converts from a Character object to a
String object. The two strings can then be concatenated using the +
operator.
We now have all the pieces ready to write the program. However, a review of
the problem statement to check we are still answering the right question
highlights a problem: the sample palindrome is only a palindrome if the case of
the letters is ignored, if the case of the letters is significant then the
sample string is not a palindrome. If our current design was applied to this
sample string, it would not be accepted as a palindrome. Given that the string
was supplied as an example of a palindrome, it must be that case is not
significant. We therefore need to address this in our design.
The answer to the problem is to convert all the characters in the input
string to lower case before testing to see if it is a palindrome. A further
search of the String class documentation provides the solution in the
form of a method declared as String toLowerCase(), which returns a lower
case version of the string it is called for. Calls to the method can be inserted
appropriately to cause case to be non-significant.
// Written by A.Person, October 2000 // Answer to Ex4 example question 4 // Program to check for a palindrome. public class Palindrome { // Return a String which is the reverse of the argument String public String reverse(final String s) { String result = new String() ; int position = 0 ; while (position < s.length()) { result = new Character(s.charAt(position)).toString() + result ; position = position + 1 ; } return result ; } // Check to see if the two argument Strings are the reverse of each // other. Return true if they are and false otherwise.. public boolean check(final String s1, final String s2) { String s = reverse(s2) ; if (s1.compareTo(s) == 0) { return true ; } else { return false ; } } // Get user to input a String. public String getInput() { KeyboardInput in = new KeyboardInput () ; System.out.print("Enter text to check: ") ; return in.readString() ; } // Do the palindrome test and display the result public void testForPalindrome(final String s) { if (check(s.toLowerCase(), s.toLowerCase())) { System.out.println("String is a palindrome.") ; } else { System.out.println("String is not a palindrome.") ; } } public static void main(final String[] args) { Palindrome myObject = new Palindrome() ; myObject.testForPalindrome(myObject.getInput()) ; } }
Note: Answers to all the questions involve writing programs consisting of one or more methods (excluding the main method).
Q4.1 Write a program that consists of the following methods:
Q4.3 Write methods to do the following:
Include the methods in an interactive program that lets the user select which conversion to perform, and then inputs a value and displays the result.
An interactive program means one that displays a simple text menu, such as:
1. Convert centimetres to feet.
2. Convert metres to yards.
3. Convert
kilometres to miles.
4. Quit
and then asks the user to type in a value from 1 to 4 to select which action to take. A loop will continually redisplay the menu until the user selects Quit (number 4) to terminate the program.
Notes: The conversion methods should take the value to be converted as a parameter and return a result. They should not do any input or display the result. Add additional methods if they will help structure the program.
Q4.4 Write a program to determine if a long integer is a palindrome (i.e., represents the same value when reversed, for example 123454321). Again, write the program using methods.
Q4.5 Write a program composed of methods to read a text file character by character and count how frequently each character occurs.
Hints: You will need to use the FileInput class, which is used in a similar
way to KeyboardInput. See the notes on using FileInput.
The FileInput .class
file needs to be in the same directory as the program you are working on. Copy
FileInput.class to all directories containing programs that need to use it.
Q4.6 Using the methods from Q4.5, write a drawing program to display a line or bar chart showing the frequency of each letter. The drawing of the chart should itself be done using a collection of methods — draw the x-axis, draw the y-axis, draw the lines/bars. Note, that the paint method should take the place of the main method of previous programs, so that all your methods are called directly or indirectly from paint.
Paint can call other methods to do drawing, providing the Graphics object is passed as a parameter to the other methods.
Q4.7 Write a program using methods that copies and reverses a text file (i.e., so that the destination file contains a backwards copy of the original file contents).
This program will need both the FileInput and FileOutput classes (described in separate notes).
Q4.8 Write a program that does the following:
Hints: the initial collections of random integers can be created and sorted
in an array. How do you sort an array? Could write your own sort method but I
wonder what the library class Arrays has to offer...
Don't forget to close
files.
Q4.9 Write a program that uses a recursive method to calculate the greatest common divisor of two numbers.
Q4.10 Write a program that reads an integer between 0 and 999 and ‘verbalizes it’. For example, if the program is given 123 it would display ‘one hundred and twenty three’.
Hint: Write methods to deal with ranges of numbers, such as single digits between ‘zero’ and ‘nine’, numbers between 10 and 19 and so on.